package com.wsoft.dc.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.wsoft.core.cmd.DcConfigService;
import com.wsoft.core.service.CommonConfigService;
import com.wsoft.core.service.CommonDictService;
import com.wsoft.core.service.ModuleService;
import com.wsoft.core.utils.LoginUserUtil;
import com.wsoft.core.vo.ConfigQuery;
import com.wsoft.core.vo.DictDataCacheVO;
import com.wsoft.core.vo.ModuleVO;
import com.wsoft.dc.entity.DcConfigEntity;
import com.wsoft.dc.entity.DcConfigEntityEntity;
import com.wsoft.dc.enums.ReadTypeEnum;
import com.wsoft.dc.manager.DcBusinessReadManager;
import com.wsoft.dc.manager.DcConfigEntityManager;
import com.wsoft.dc.manager.DcConfigManager;
import com.wsoft.dc.query.config.ConfigListQuery;
import com.wsoft.dc.query.dc.DcListQuery;
import com.wsoft.dc.query.dc.DcPortalQuery;
import com.wsoft.dc.service.IDcService;
import com.wsoft.dc.vo.ConfigEntityVO;
import com.wsoft.dc.vo.PortalCountVO;
import com.wsoft.entity.BaseConfigVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author z001
 * @Date 2024/12/18 15:45
 */
@Service
@Slf4j
public class DcServiceImpl implements IDcService {

    @Resource
    private DcConfigManager configManager;
    @Resource
    private DcConfigEntityManager configEntityManager;
    @Resource
    private DcBusinessReadManager readManager;
    @Resource
    private ModuleService moduleService;
    @Autowired
    private ApplicationContext applicationContext;
    @Resource
    private CommonConfigService commonConfigService;
    @Resource
    private CommonDictService commonDictService;

    /**
     * 待办类型 字典code
     */
    private final String DCTYPE = "DCTYPE";
    /**
     * 门户 config表 默认名称和icon
     */
    private final String PORTAL_DEFAULT_NAME_ICON = "portal_default_name_icon";

    /**
     * 待办分页查询
     *
     * @param query
     * @return
     */
    @Override
    public Map<String, Object> dcList(DcListQuery query,boolean isPage) {
        Map<String, Object> resultMap = new HashMap<>(16);
        //查询已启用的
        List<ModuleVO> moduleList = moduleService.listModuleAll(1);
        if (CollUtil.isEmpty(moduleList)) {
            return new HashMap<>(16);
        }
        List<Long> moduleIdList = moduleList.stream().map(ModuleVO::getId).collect(Collectors.toList());
        ConfigListQuery configListQuery = new ConfigListQuery();
        configListQuery.setModuleId(query.getModuleId());
        configListQuery.setType(query.getType());
        //查询已启用的
        configListQuery.setIsEnable(1);
        List<DcConfigEntity> configList = configManager.listConfig(configListQuery);
        // 按照 moduleIdList 中的顺序对 configList 进行排序
        configList = configList.stream()
                .sorted(Comparator.comparingInt(entity -> moduleIdList.indexOf(entity.getModuleId())))
                .collect(Collectors.toList());

        //对应每个config的个数集合
        List<Long> countList = new ArrayList<>();

        //所有共有属性 和搜索参数
        getAttributes(configList, resultMap);

        //查询全部
        if (null == query.getIsRead() || query.getIsRead().equals(ReadTypeEnum.ALL.getType())) {
            //总条数
            Long totalCount = getTotalCount(configList, query.getParamMap(), countList);
            resultMap.put("totalCount", totalCount);
            if(isPage){
                //查询全部
                List<BaseConfigVO> dataList = getDataList(configList, query.getParamMap());
                resultMap.put("dataList", dataList.stream().skip((long) query.getPageSize() * (query.getPageNum() - 1)).limit(query.getPageSize()).collect(Collectors.toList()));
            }else{
                List<BaseConfigVO> dataList = getDataList(configList, query.getParamMap());
                resultMap.put("dataList", dataList);
            }

        } else {
            //处理有已读未读搜索条件
            List<BaseConfigVO> dataList = new ArrayList<>();
            Long totalCount = 0L;
            totalCount = getDataList(dataList, totalCount, configList, query.getParamMap(), query.getIsRead());

            //手动分页
            resultMap.put("totalCount", totalCount);
            if(isPage){
                resultMap.put("dataList", dataList.stream().skip((long) query.getPageSize() * (query.getPageNum() - 1)).limit(query.getPageSize()).collect(Collectors.toList()));
            }else{
                resultMap.put("dataList", dataList);
            }
        }

        return resultMap;
    }



    /**
     * 门户 查询 待办个数
     *
     * @param query
     * @return
     */
    @Override
    public List<PortalCountVO> portalCount(DcPortalQuery query) {
        List<PortalCountVO> result = new ArrayList<>();


        // 将 JSON 字符串转换为 List<Map<String, Object>>
        List<Map<String, Object>> list = JSON.parseObject(query.getModuleJson(), new TypeReference<List<Map<String, Object>>>() {
        });
        for (Map<String, Object> map : list) {
            PortalCountVO vo = new PortalCountVO();
            Long moduleId = ObjUtil.isEmpty(map.get("module")) ? null : Long.valueOf(map.get("module").toString());
            String type = ObjUtil.isEmpty(map.get("type"))? "" : map.get("type").toString();


            vo.setType(type);
            vo.setModuleId(moduleId);
            //调用dc
            ConfigListQuery configListQuery = new ConfigListQuery();
            if(null != moduleId){
                configListQuery.setModuleId(Collections.singletonList(moduleId));
            }
            if(StrUtil.isNotBlank(type)){
                configListQuery.setType(Collections.singletonList(type));
            }
            //查询已启用的
            configListQuery.setIsEnable(1);
            List<DcConfigEntity> configList = configManager.listConfig(configListQuery);
            Long totalCount = getTotalCount(configList, new HashMap<>(1), new ArrayList<>());

            if (null == moduleId && StrUtil.isBlank(type)) {
                //都为空,取config 默认
                Map<String, String> configMap = getDefaultPortal();
                vo.setName(configMap.get("name"));
                vo.setIcon(configMap.get("icon"));
            } else if (null == moduleId && StrUtil.isNotBlank(type)) {
                //都为空,取config 默认
                ConfigQuery configQuery = new ConfigQuery();
                configQuery.setCode(PORTAL_DEFAULT_NAME_ICON);
                //查询type名称
                DictDataCacheVO dataCacheVO = getDictTypeValue(type);
                vo.setName(dataCacheVO.getName());
                vo.setIcon(dataCacheVO.getIcon());

            } else if (null != moduleId && StrUtil.isBlank(type)) {
                ModuleVO moduleVO = moduleService.getByModuleId(moduleId);
                vo.setName(moduleVO.getName());
                vo.setIcon(moduleVO.getIcon());
            } else {
                ModuleVO moduleVO = moduleService.getByModuleId(moduleId);
                //查询type名称
                DictDataCacheVO dataCacheVO = getDictTypeValue(type);
                vo.setName(moduleVO.getName() + StrUtil.DASHED + dataCacheVO.getName());

                List<DcConfigEntity> collect = configList.stream().filter(item -> item.getType().equals(type) && item.getModuleId().equals(moduleId)).collect(Collectors.toList());
                if(CollUtil.isNotEmpty(collect)){
                    vo.setIcon(collect.get(0).getIcon());
                }else{
                    vo.setIcon(dataCacheVO.getIcon());
                }


            }

            vo.setCount(totalCount);
            result.add(vo);
        }
        return result;
    }

    /**
     * 首页弹框-查询待办个数
     * @return
     */
    @Override
    public Long homeCount() {
        //查询config表 查询已启用和待处理的
        ConfigListQuery query = new ConfigListQuery();
        query.setIsPendingProcess(1);
        query.setIsEnable(1);
        List<DcConfigEntity> configList = configManager.listConfig(query);
        return getTotalCount(configList, null, new ArrayList<>());
    }

    // ################################## 私有方法  ##################################


    /**
     * 获取config表中 默认的 portal名称和icon
     *
     * @param vo
     */
    private Map<String, String> getDefaultPortal() {
        //都为空,取config 默认
        ConfigQuery configQuery = new ConfigQuery();
        configQuery.setCode("portal_default_name_icon");
        return commonConfigService.getConfigValue(configQuery);
    }

    /**
     * 获取 待办中心类型字典
     *
     * @param type
     * @return
     */
    private DictDataCacheVO getDictTypeValue(String type) {
        List<DictDataCacheVO> dict = commonDictService.getDictByCode(DCTYPE);
        if (CollUtil.isEmpty(dict)) {
            return new DictDataCacheVO();
        }
        List<DictDataCacheVO> collect = dict.stream().filter(item -> item.getCode().equals(type)).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return new DictDataCacheVO();
        }
        return collect.get(0);
    }


    /**
     * 获取 需要查询待办list 的索引值
     *
     * @param countList
     * @param pageNo
     * @param pageSize
     * @return
     */
    public List<Integer> getListIndex(List<Long> countList, int pageNo, int pageSize) {
        int start = pageSize * (pageNo - 1);
        int startNum = start + 1;
        int endNum = startNum + pageSize;
        long count = 0L;

        List<Integer> resultList = new ArrayList<>();
        for (int i = 0; i < countList.size(); i++) {
            count = count + countList.get(i);
            //如果在区间内,则记录索引值,被记录的索引值,用户后续查询该记录列表
            if (count > endNum) {
                resultList.add(i);
                break;
            } else if ((int) count >= startNum && (int) count <= endNum) {
                resultList.add(i);
            } else if (count < startNum) {
                continue;
            }
        }
        return resultList;

    }


    /**
     * 调用所有方法的 count方法
     *
     * @param configList
     */
    private Long getTotalCount(List<DcConfigEntity> configList, Map<String, Object> paramMap, List<Long> countList) {
        long totalCount = 0L;
        for (DcConfigEntity entity : configList) {
            DcConfigService dcConfigService = getConfigService(entity.getCountInterface());
            Long count = dcConfigService.count(paramMap);
            countList.add(count);
            totalCount = totalCount + count;
        }
        return totalCount;
    }


    /**
     * 获取数据列表
     * 获取待办 数据 列表 ==> listIndex 按需查找
     *
     * @param configList 配置列表
     * @param listIndex  列表索引
     * @param paramMap   param地图
     * @return {@link List}<{@link BaseConfigVO}>
     */
    private List<BaseConfigVO> getDataList(List<DcConfigEntity> configList, Map<String, Object> paramMap) {
        List<BaseConfigVO> resultList = new ArrayList<>();
        for (int i = 0; i < configList.size(); i++) {
            DcConfigEntity configEntity = configList.get(i);
            DcConfigService dcConfigService = getConfigService(configEntity.getListInterface());
            try {
                List<? extends BaseConfigVO> list = dcConfigService.list(paramMap);
                //处理数据
                Long memberId = LoginUserUtil.getUserInfo().getLoginUserVO().getId();
                handlerData(memberId, list, configEntity);

                if (CollUtil.isNotEmpty(list)) {
                    //分页
                    list = list.stream().peek(item -> item.setConfigId(configEntity.getId())).collect(Collectors.toList());
                    resultList.addAll(list);
                }
            } catch (Exception e) {
                log.error("待办中心获取数据异常,异常信息为:{}", e);
            }
        }
        return resultList;
    }

    /**
     * 有已读未读 搜索条件下 获取数据列表
     *
     * @param dataList   返回的数据列表
     * @param totalCount 总个数
     * @param configList 配置列表
     * @param paramMap   参数
     * @param isRead     是否已读
     * @return
     */
    private Long getDataList(List<BaseConfigVO> dataList, Long totalCount, List<DcConfigEntity> configList, Map<String, Object> paramMap, Integer isRead) {
        Long memberId = LoginUserUtil.getUserInfo().getLoginUserVO().getId();
        for (DcConfigEntity config : configList) {
            Set<String> readSet = readManager.getMemberRead(memberId, config.getId());
            if (CollUtil.isEmpty(readSet) && ReadTypeEnum.READ.getType().equals(isRead)) {
                //已读表为空,且查询已读
                continue;
            }
            DcConfigService dcConfigService = getConfigService(config.getListInterface());
            List<? extends BaseConfigVO> list = dcConfigService.list(paramMap);
            if (CollUtil.isEmpty(list)) {
                //数据为空
                continue;
            }
            //处理数据
            handlerData(memberId, list, config);
            if (ReadTypeEnum.READ.getType().equals(isRead)) {
                //已读
                List<? extends BaseConfigVO> collect = list.stream().filter(BaseConfigVO::getRead).collect(Collectors.toList());
                dataList.addAll(collect);
                totalCount = totalCount + (long) collect.size();
            } else  if(ReadTypeEnum.UNREAD.getType().equals(isRead)){
                //未读
                List<? extends BaseConfigVO> collect = list.stream().filter(item -> !item.getRead()).collect(Collectors.toList());
                dataList.addAll(collect);
                totalCount = totalCount + (long) collect.size();
            } else{
                //查询全部
                dataList.addAll(list);
                totalCount = totalCount + (long) list.size();
            }
        }
        return totalCount;
    }



    /**
     * 构建 组件/路由 地址, 构建跳转方式,构建
     *
     * @param dataList 数据列表
     * @param openPage 填充地址
     * @param openType 跳转方式
     */
    private void handlerData(Long memberId, List<? extends BaseConfigVO> dataList, DcConfigEntity configEntity) {
        if (CollUtil.isEmpty(dataList)) {
            return;
        }
        //子项列表
        List<DcConfigEntityEntity> configEntityList = configEntityManager.listConfigEntity(configEntity.getId());
        List<DcConfigEntityEntity> keyList = configEntityList.stream().filter(item -> item.getIsKey() == 1).collect(Collectors.toList());

        //已读列表
        Set<String> readSet = readManager.getMemberRead(memberId, configEntity.getId());

        dataList.forEach(item -> {
            //填充跳转方式
            item.setOpenType(configEntity.getOpenType());
            //填充url
            item.setUrl(fillUrl(configEntity.getOpenPage(), item));
            item.setConfigId(configEntity.getId());
            //填充待办id
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("configId", configEntity.getId());
            if (CollUtil.isNotEmpty(keyList)) {
                for (DcConfigEntityEntity entity : keyList) {
                    Map<String, Object> userMap = JSON.parseObject(JSON.toJSONString(item), new TypeReference<Map<String, Object>>() {
                    });
                    jsonObject.put(entity.getAttribute(), userMap.get(entity.getAttribute()));
                }
            }
            item.setTodoId(jsonObject.toJSONString());
            //是否已读
            if(null != configEntity.getIsPendingProcess() && configEntity.getIsPendingProcess() == 1){
                item.setRead(readSet.contains(jsonObject.toJSONString()));
            }else{
                //非待处理接口,直接返回已读
                item.setRead(true);
            }
        });
    }


    /**
     * 填充 url
     *
     * @param url 要填充的url
     * @param obj 填充的类数据
     * @return
     */
    private static String fillUrl(String url, Object obj) {
        // 使用正则表达式匹配 [属性名] 格式的占位符
        Pattern pattern = Pattern.compile("\\[([^\\]]+)\\]");
        Matcher matcher = pattern.matcher(url);

        // 创建一个 StringBuilder 来构建填充后的 URL
        StringBuilder filledUrl = new StringBuilder();

        // 记录上一次匹配的结束位置
        int lastEnd = 0;

        // 遍历所有匹配的占位符
        while (matcher.find()) {
            // 将匹配前的部分添加到结果中
            filledUrl.append(url, lastEnd, matcher.start());

            // 获取占位符中的属性名
            String fieldName = matcher.group(1);

            try {
                // 使用反射获取对象的属性值
                Field field = obj.getClass().getDeclaredField(fieldName);
                // 允许访问私有属性
                field.setAccessible(true);
                Object value = field.get(obj);

                // 将属性值添加到结果中
                filledUrl.append(value);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                // 如果属性不存在或无法访问，保留原始占位符
                filledUrl.append(matcher.group(0));
            }
            // 更新上一次匹配的结束位置
            lastEnd = matcher.end();
        }
        // 将剩余的部分添加到结果中
        filledUrl.append(url.substring(lastEnd));
        return filledUrl.toString();
    }

    /**
     * 获取所有entity表的 共有属性
     *
     * @param configList
     * @return
     */
    private List<ConfigEntityVO> getAllPublicAttributes(List<DcConfigEntity> configList, boolean isSearch) {
        Map<String, String> allMap = new HashMap<>(16);
        List<String> allList = new ArrayList<>();
        for (DcConfigEntity entity : configList) {
            List<DcConfigEntityEntity> entityList = configEntityManager.listConfigEntity(entity.getId());
            List<DcConfigEntityEntity> collect = entityList.stream().filter(item -> {
                if (isSearch) {
                    return 1 == item.getIsQuery();
                } else {
                    return true;
                }
            }).collect(Collectors.toList());
            //属性列表
            List<String> attributeList = collect.stream().map(DcConfigEntityEntity::getAttribute).collect(Collectors.toList());
            allList.addAll(attributeList);
            //属性map,对应显示标题
            Map<String, String> attributeMap = collect.stream().collect(Collectors.toMap(DcConfigEntityEntity::getAttribute, DcConfigEntityEntity::getTitle));
            allMap.putAll(attributeMap);
        }
        if(CollUtil.isEmpty(allList)){
            return new ArrayList<>();
        }
        //查出公共属性
        List<String> collect = allList.stream()
                // 筛选出出现次数等于列表数量的元素
                .filter(element -> Collections.frequency(allList, element) == configList.size())
                .distinct() // 去重
                .collect(Collectors.toList());
        //赋值显示名称
        List<ConfigEntityVO> result = new ArrayList<>();
        for (String key : collect) {
            ConfigEntityVO vo = new ConfigEntityVO();
            vo.setAttribute(key);
            vo.setTitle(allMap.get(key));
            result.add(vo);
        }
        return result;
    }

    /**
     * 获取待办共有属性 和 搜索参数
     * @param configList
     * @param resultMap
     */
    private void getAttributes(List<DcConfigEntity> configList,Map<String, Object> resultMap){
        // 使用线程池
        ExecutorService executorService = new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(10));

        // 异步调用 getAllPublicAttributes
        CompletableFuture<List<ConfigEntityVO>> attributesFuture = CompletableFuture.supplyAsync(() -> getAllPublicAttributes(configList, false), executorService);
        CompletableFuture<List<ConfigEntityVO>> searchAttributesFuture = CompletableFuture.supplyAsync(() -> getAllPublicAttributes(configList, true), executorService);

        // 等待所有任务完成
        CompletableFuture.allOf(attributesFuture, searchAttributesFuture).join();

        try {
            // 获取结果并放入 resultMap
            resultMap.put("attributesList", attributesFuture.get());
            resultMap.put("searchAttributesList", searchAttributesFuture.get());
        } catch (InterruptedException | ExecutionException e) {
            log.error("Error getting attributes", e);
        }

        // 关闭线程池
        executorService.shutdown();

    }

    /**
     * 动态获取bean
     *
     * @param beanName
     * @return
     */
    public DcConfigService getConfigService(String beanName) {
        // 动态获取 Bean
        return getBean(beanName);
    }

    public <T> T getBean(String beanName) {
        return (T) applicationContext.getBean(beanName);
    }
}
